#include "DeviceManager.h"
#include "File.hpp"
#include "StringUtil.hpp"
#include "StringCast.hpp"
#include "../Object/GatewayInfo.h"
#include "../Object/DeviceInfo.h"
#include <unordered_map>

namespace
{
#define GATEWAY_CSV_CLOUMN 2
#define DEVICE_CSV_COLUMN 2
} // namespace

//DeviceManagerData
class DeviceManagerData
{
public:
    DeviceManagerData() = default;

private:
    friend class DeviceManager;
    void loadDevice();
    void loadGatewayInfo();
    void loadDeviceInfo();

    void processLineGatewayData(const std::string &data);
    void processLineDeviceData(const std::string &data);

private:
    std::unordered_map<uint16_t, GatewayInfo> gatewayInfoMap;
    std::unordered_map<uint16_t, DeviceInfo> deviceInfoMap;
};

void DeviceManagerData::loadDevice()
{
    loadGatewayInfo();
    loadDeviceInfo();
}

void DeviceManagerData::loadGatewayInfo()
{
    std::string gateway_csv = "gateway.csv";
    sh::File file(gateway_csv);
    if (file.open(std::ios_base::in))
    {
        bool is_title = true;
        std::string line_content;
        while (!file.endOfFile())
        {
            line_content = file.readLine(1024);
            if (line_content.empty())
            {
                break;
            }
            if (is_title)
            {
                is_title = false;
                continue;
            }
            processLineGatewayData(line_content);
        }
    }
}

void DeviceManagerData::loadDeviceInfo()
{
    std::string gateway_csv = "device.csv";
    sh::File file(gateway_csv);
    if (file.open(std::ios_base::in))
    {
        bool is_title = true;
        std::string line_content;
        while (!file.endOfFile())
        {
            line_content = file.readLine(1024);
            if (line_content.empty())
            {
                break;
            }
            if (is_title)
            {
                is_title = false;
                continue;
            }
            processLineDeviceData(line_content);
        }
    }
}

void DeviceManagerData::processLineGatewayData(const std::string &data)
{
    std::vector<std::string> split_data = sh::StringUtil::split(data, ",");
    if (GATEWAY_CSV_CLOUMN != split_data.size())
    {
        return;
    }
    std::string id_str = split_data.at(0);
    std::string host_str = split_data.at(1);

    uint16_t id = sh::StringCast::toUInt(id_str);

    GatewayInfo gateway_info(host_str, id);
    gatewayInfoMap.insert(std::make_pair(id, gateway_info));
}

void DeviceManagerData::processLineDeviceData(const std::string &data)
{
    std::vector<std::string> split_data = sh::StringUtil::split(data, ",");
    if (GATEWAY_CSV_CLOUMN != split_data.size())
    {
        return;
    }
    std::string id_str = split_data.at(0);
    std::string gateway_id_str = split_data.at(1);

    uint8_t id = sh::StringCast::toUInt(id_str);
    uint16_t gateway_id = sh::StringCast::toUInt(gateway_id_str);

    auto gateway_itor = gatewayInfoMap.find(gateway_id);
    if (gatewayInfoMap.end() == gateway_itor)
    {
        return;
    }
    DeviceInfo device(gateway_itor->second, id);
    deviceInfoMap.insert(std::make_pair(gateway_id, device));
}

//DeviceManager
std::unique_ptr<DeviceManager>
    DeviceManager::m_deviceManager = std::unique_ptr<DeviceManager>(new DeviceManager());

DeviceManager *DeviceManager::getDeviceManagerInstance()
{
    return m_deviceManager.get();
}

DeviceManager::~DeviceManager()
{
}
DeviceManager::DeviceManager()
{
    d = std::unique_ptr<DeviceManagerData>(new DeviceManagerData());
    d->loadDevice();
}
